\subsection{Вычисление среднего арифметического}

Представим, что нам нужно вычислить \glslink{arithmetic mean}{среднее арифметическое}, 
и по какой-то странной причине, 
нам нужно задать все числа в аргументах функции.

Но в \CCpp функции с переменным кол-вом аргументов невозможно определить кол-во аргументов,
так что обозначим значение $-1$ как конец списка.%

\subsubsection{Используя макрос va\_arg}

Имеется стандартный заголовочный файл stdarg.h, который определяет макросы для работы с такими аргументами.

Их так же используют функции \printf и \scanf.

\lstinputlisting[style=customc]{\CURPATH/arith_RU.c}

Самый первый аргумент должен трактоваться как обычный аргумент.

\myindex{\CStandardLibrary!va\_arg}
Остальные аргументы загружаются используя макрос \TT{va\_arg}, и затем суммируются.

Так что внутри?

\myparagraph{Соглашение о вызовах \IT{cdecl}}

\lstinputlisting[caption=\Optimizing MSVC 6.0,style=customasmx86]{\CURPATH/arith_MSVC60_Ox_RU.asm}

Аргументы, как мы видим, передаются в \main один за одним.

Первый аргумент заталкивается в локальный стек первым.

Терминатор (оконечивающее значение $-1$) заталкивается последним.

Функция \TT{arith\_mean()} берет первый аргумент и сохраняет его значение в переменной $sum$.

Затем, она записывает адрес второго аргумента в регистр \EDX, берет значение оттуда, прибавляет к $sum$,
и делает это в бесконечном цикле, до тех пор, пока не встретится $-1$.

Когда встретится, сумма делится на число всех значений (исключая $-1$) и \glslink{quotient}{частное} 
возвращается.

Так что, другими словами, я бы сказал, функция обходится с фрагментом стека как с массивом целочисленных
значений, бесконечной длины.

Теперь нам легче понять почему в соглашениях о вызовах \IT{cdecl} первый аргумент 
заталкивается в стек последним.

Потому что иначе будет невозможно найти первый аргумент, или, для функции вроде \printf, невозможно
будет найти строку формата.

\myparagraph{Соглашения о вызовах на основе регистров}
\label{variadic_arith_registers}

Наблюдательный читатель может спросить, что насчет тех соглашений о вызовах, где первые аргументы передаются
в регистрах?

Посмотрим:

\lstinputlisting[caption=\Optimizing MSVC 2012 x64,style=customasmx86]{\CURPATH/arith_MSVC_2012_Ox_x64_RU.asm}

Мы видим, что первые 4 аргумента передаются в регистрах и еще два --- в стеке.

Функция \TT{arith\_mean()} в начале сохраняет эти 4 аргумента в \IT{Shadow Space} и затем обходится
с \IT{Shadow Space} и стеком за ним как с единым непрерывным массивом!

Что насчет GCC? Тут немного неуклюже всё, потому что функция делится на две части: первая часть
сохраняет регистры в \q{red zone}, обрабатывает это пространство, а вторая часть функции обрабатывает стек:

\lstinputlisting[caption=\Optimizing GCC 4.9.1 x64,style=customasmx86]{\CURPATH/arith_GCC491_x64_O3_RU.s}

Кстати, похожее использование \IT{Shadow Space} разбирается здесь: \myref{pointer_to_argument}.

\subsubsection{Используя указатель на первый аргумент ф-ции}

Пример можно переписать без использования макроса \TT{va\_arg}:

\lstinputlisting[style=customc]{\CURPATH/arith2.c}

Иными словами, если набор аргументов -- это массив слов (32-битных или 64-битных), то мы просто перебираем элементы
этого массива, начиная с первого.

